<?php
/**
 * User: @lose
 * Date: 2020-04-01
 * Time: 17:28
 */

namespace Buu\Modules\AutoLdap\Controllers;

use App\Http\Controllers\Controller;
use App\Pockets\GridDataModel as pGridDataModel;
use Doraemon\model\ImageCreate\ImageCreate;
use Doraemon\model\Ldap\LdapGroup;
use Doraemon\model\Ldap\LdapRelated;
use Doraemon\service\Ldap\Schedule;
use Doraemon\tools\Mail;
use Doraemon\tools\Openldap;
use Encore\Admin\Facades\Admin;
use Encore\Admin\Layout\Content;
use Encore\Admin\Grid;
use Encore\Admin\Widgets\Form;
use Illuminate\Http\Request;
use Illuminate\Support\MessageBag;
use Doraemon\service\Ldap\Schedule as sLSchedule;


class IndexController extends Controller
{
    public function initLdap(Content $content, Request $request)
    {
        Schedule::initLdapInfo();
        die;
    }

    public function department(Content $content, Request $request)
    {
        $requestData = $request->all();

        $requestData["type"] = Schedule::GROUP_TYPE_DEPARTMENT_INDEX;

        $where = $this->buildWhere($requestData);
        $page = $request->input('page', 1);
        $pageSize = $request->input('per_page', 10);
        $limit = [
            ($page - 1) * $pageSize,
            $pageSize
        ];

        $list = sLSchedule::getList($where, $limit);

        return $content
            ->header('Ldap部门管理')
            ->breadcrumb(['text' => '部门列表'])
            ->row($this->_formatGrid($list, $page, $pageSize, $where));
    }

    // 删除项目组
    public function deleteProjectGroup(Request $request, $id)
    {
        $projectInfo = LdapGroup::getDataById($id);
        $cn = $projectInfo["name"];

        $updateData = array(
            "i_status" => LdapGroup::STATUS_DELETE,
        );
        $rs = LdapGroup::saveInfo($id, $updateData);

        if ($rs) {
            // 删除ldap中的项目组
            $provider = Openldap::getLdapProvider();
            Openldap::deleteEntry($provider, $cn);
            // 删除项目关联关系
            $updateWhere = array(
                "project_id" => $id
            );

            $updateData = array(
                "i_status" => LdapRelated::STATUS_DELETE,
            );
            $rs = LdapRelated::update($updateData, $updateWhere);

            if ($rs) {
                return response()->json([
                    'status'  => true,
                    'message' => "删除成功",
                ]);
            }
        }

        return response()->json([
            'status'  => false,
            'message' => "删除失败",
        ]);
    }

    public function project(Content $content, Request $request)
    {
        $requestData = $request->all();
        $requestData["type"] = Schedule::GROUP_TYPE_PROJECT_INDEX;

        $where = $this->buildWhere($requestData);
        $page = $request->input('page', 1);
        $pageSize = $request->input('per_page', 10);
        $limit = [
            ($page - 1) * $pageSize,
            $pageSize
        ];

        $list = sLSchedule::getList($where, $limit);

        return $content
            ->header('Ldap项目管理')
            ->breadcrumb(['text' => '组列表'])
            ->row($this->_formatGrid($list, $page, $pageSize, $where));
    }

    // 具体模板列表内容排布
    public function _formatGrid($list, $page, $pageSize, $where)
    {
        $options = array(
            "currentPage" => $page,
            "perPage"     => $pageSize,
        );

        $gridModel = new pGridDataModel($list['list'], $list['total'], $options);

        $grid = Admin::grid($gridModel,
            function (Grid $grid) use ($pageSize, $where) {

                $grid->paginate($pageSize);
                $grid->filter(function (Grid\Filter $filter) {
                    $filter->disableIdFilter();
                    $filter->column(1 / 2, function (Grid\Filter $filter) {
                        $filter->equal('title', '标题')->placeholder('输入标题关键字');
                    });
                });

                $grid->disableExport();
                $grid->disableRowSelector();

                $grid->column('id', 'id');

                $grid->column('name', '名字');

                $grid->column('type', '类型')->display(function () {
                    return \Doraemon\service\Ldap\Schedule::GROUP_TYPE[$this->type];
                });

                if (isset($where["type"]) && $where["type"] == Schedule::GROUP_TYPE_DEPARTMENT_INDEX) {
                    $grid->actions(function (Grid\Displayers\Actions $actions) {
                        $actions->disableDelete();
                    });
                } else {
                    $grid->actions(function (Grid\Displayers\Actions $actions) {
                        $actions->disableEdit();
                    });
                }
            }
        );

        if (isset($where["type"]) && $where["type"] == Schedule::GROUP_TYPE_DEPARTMENT_INDEX) {
            $grid->disableCreateButton();
        }
        return $grid;
    }

    // 构建查询条件
    private function buildWhere($params)
    {
        $where = [];

        if (isset($params["i_status"]) && $params["i_status"]) {
            $where['i_status'] = $params["i_status"];
        } else {
            $params["i_status"] = ImageCreate::STATUS_NORMAL;
            $where['i_status'] = $params["i_status"];
        }

        if (isset($params['title']) && $params['title']) {
            $where['name[~]'] = $params['title'];
        }

        if (isset($params['type']) && $params['type']) {
            $where['type'] = $params['type'];
        }

        return $where;
    }

    // 组修改
    public function groupEdit(Content $content, Request $request, $id = 0)
    {
        //基础信息
        $baseInfoForm = $this->_getGroupBaseInfoForm($id);

        $content->header('组列表')
            ->breadcrumb([
                'text' => '组编辑',
                'url'  => '/AutoLdap/department'
            ], ['text' => '组编辑'])
            ->row($baseInfoForm);

        return $content;
    }

    // 保存组信息
    public function saveGroupInfo(Request $request)
    {
        $provider = Openldap::getLdapProvider();

        $id = $request->get("id", 0);

        $relatedProjectIds = array_filter($request->get("related_project_ids", array()));
        $dbRelatedProjectIds = \Doraemon\service\Ldap\Schedule::getGroupRelatedIds($id);

        $deleteProjectIds = array_diff($dbRelatedProjectIds, $relatedProjectIds);
        $addProjectIds = array_diff($relatedProjectIds, $dbRelatedProjectIds);

        foreach ($deleteProjectIds as $deleteProjectId) {
            $addData = array(
                "i_status" => LdapRelated::STATUS_DELETE,
                "edittime" => time(),
            );

            $where = array(
                "org_id"     => $id,
                "project_id" => $deleteProjectId,
            );

            LdapRelated::saveByWhere($where, $addData);
        }

        foreach ($addProjectIds as $addProjectId) {
            $addData = array(
                "org_id"     => $id,
                "project_id" => $addProjectId,
                "i_status"   => LdapRelated::STATUS_NORMAL,
                "addtime"    => time(),
            );

            $rs = LdapRelated::addInfo($addData);

            // 将部门中的用户移入 项目组
            if ($rs) {
                Openldap::addMemberFromDepartToProject($provider, $id, $addProjectId);
            }
        }

        $success = new MessageBag([
            'title' => '保存成功'
        ]);
        return redirect(url("/admin/AutoLdap/department/{$id}/edit"))->with(compact('success'));
    }


    private function _getGroupBaseInfoForm($id = 0)
    {
        $info = [];
        if ($id) {
            $info = \Doraemon\service\Ldap\Schedule::getGroupInfo($id);
        }

        $baseInfoForm = new Form($info);

        $baseInfoForm->hidden("id", "group id");

        $baseInfoForm->multipleSelect('related_project_ids', '关联项目')
            ->options($info['related_project'] ?? [])
            ->ajax('/admin/AutoLdap/searchproject')
            ->help('输入关键词搜索');

        $baseInfoForm->action('/admin/AutoLdap/savegroupinfo');
        return $baseInfoForm;
    }

    /** 项目组搜索
     * @param Request $request
     * @return \Illuminate\Http\JsonResponse
     */
    public function searchProject(Request $request)
    {
        $keyword = $request->input('q', ' ');
        $result = LdapGroup::getGroupByName($keyword, array(Schedule::GROUP_TYPE_PROJECT_INDEX));

        $tags = [
            "total"         => 4,
            "per_page"      => 15,
            "current_page"  => 1,
            "last_page"     => 1,
            "next_page_url" => null,
            "prev_page_url" => null,
            "from"          => 1,
            "to"            => 3,
        ];

        $tags['data'] = array_map(function ($res) {
            return [
                'id'   => $res['id'],
                'text' => $res['name'],
            ];
        }, $result);

        return response()->json($tags);
    }

    /**
     * 创建组
     * @param Content $content
     * @return Content
     */
    public function createGroup(Content $content)
    {
        $form = $this->_getModuleForm(null);
        return $content
            ->header('添加项目')
            ->breadcrumb([
                'text' => '项目列表',
                'url'  => '/AutoLdap/project'
            ], ['text' => '添加项目'])
            ->row($form);
    }

    /**
     * 创建组
     * @param $pageId
     * @param $moduleInfo
     * @param int $moduleType
     * @return Form
     */
    private function _getModuleForm($formInfo)
    {
        $form = new Form($formInfo);
        $form->hidden('id', '图片模块id');
        $form->text('name', '组名')->required()->default("")->help('请输入组的名称');

        $form->action("/admin/AutoLdap/createGroup");
        return $form;
    }

    // 创建组
    public function saveGroup(Request $request)
    {
        $name = $request->input('name', '');
        $type = $request->input('type', \Doraemon\service\Ldap\Schedule::GROUP_TYPE_PROJECT_INDEX);

        $addData = array(
            "type"     => $type,
            "name"     => $name,
            "i_status" => LdapGroup::STATUS_NORMAL,
        );

        LdapGroup::addInfo($addData);

        $provide = Openldap::getLdapProvider();
        Openldap::addGroup($provide, $name);

        $success = new MessageBag([
            'title' => '保存成功'
        ]);
        return redirect(url("/admin/AutoLdap/project"))->with(compact('success'));
    }

    private function initUserOpenVpn($email)
    {
        $organizationId = '58118199453288061edb25dd';
        $users = $this->PritunlApi('get', "/user/{$organizationId}");
        $findUser = null;
        $serverId = null;
        foreach ($users as $user) {
            $serverId = $user['servers'][0]['id'];
            if ($user['email'] == $email) {
                $findUser = $user;
                //用户已被禁用 启用
                if ($user['disabled']) {
                    $this->PritunlApi('put', "/user/{$organizationId}/{$user['id']}", [
                        'name'         => $email,
                        'email'        => $email,
                        'organization' => $organizationId,
                        'disabled'     => false
                    ]);
                }
                break;
            }
        }
        if (!$findUser) {
            $users = $this->PritunlApi('post', "/user/{$organizationId}", [
                'name'         => $email,
                'email'        => $email,
                'organization' => $organizationId
            ]);
            $findUser = $users[0];
        }
        $keyUrl = $this->PritunlApi('get', "/key/{$organizationId}/{$findUser['id']}");
        $openvpnConfigPath = sys_get_temp_dir() . DIRECTORY_SEPARATOR . $email . ".ovpn";
        file_put_contents($openvpnConfigPath, file_get_contents("https://pritunl.haohaozhu.me/key/{$keyUrl['id']}/{$serverId}.key"));
        Mail::send($email, 'VPN开通通知', '<p class="xsj_paragraph xsj_paragraph_level_0" data-source-line="0" data-source-line-display="true">附件是你的VPN配置文件</p>
<p class="xsj_paragraph xsj_paragraph_level_0" data-source-line="2" data-source-line-display="true">VPN是在除公司网络环境以外场景（例如：在家办公、出差等）登录各种公司内部系统（例如：jira、confluece、各类管理后台等）的基本先决条件</p>
<p class="xsj_paragraph xsj_paragraph_level_0" data-source-line="4" data-source-line-display="true">建议有相关需求的同事尽快安装和检查VPN是否能够正常连接</p>
<p class="xsj_paragraph xsj_paragraph_level_0" data-source-line="6" data-source-line-display="true">具体的安装和使用可以参照下面企业微信微盘中的使用说明文档</p>
<p class="xsj_paragraph xsj_paragraph_level_0" data-source-line="8" data-source-line-display="true">
  <strong class="markdown_strong_asterisk">
    <span class="mark mark_color mark_color_F44336" style="color: rgb(244, 67, 54); background-color: rgba(244, 67, 54, 0.1);">VPN账号一人一号，请妥善保管自己的配置文件，严禁共享使用</span>
  </strong>
</p>
<p class="xsj_paragraph xsj_paragraph_level_0" data-source-line="10" data-source-line-display="true">有其他问题可以企业微信联系 徐冠群</p>
<p class="xsj_paragraph xsj_paragraph_level_0" data-source-line="12" data-source-line-display="true"><a href="https://drive.weixin.qq.com/s?k=AKgAHAfHAAkyaihlMrAEMAPwYbAIo" class="xsj_link xsj_auto_link">https://drive.weixin.qq.com/s?k=AKgAHAfHAAkyaihlMrAEMAPwYbAIo</a>
</p>', $openvpnConfigPath);
        unlink($openvpnConfigPath);
    }

    private function disableUserOpenVpn($email)
    {
        $organizationId = '58118199453288061edb25dd';
        $users = $this->PritunlApi('get', "/user/{$organizationId}");
        foreach ($users as $user) {
            $serverId = $user['servers'][0]['id'];
            if ($user['email'] == $email) {
                $users = $this->PritunlApi('put', "/user/{$organizationId}/{$user['id']}", [
                    'name'         => $email,
                    'email'        => $email,
                    'organization' => $organizationId,
                    'disabled'     => true
                ]);
            }
        }
    }


    private function PritunlApi($method, $path, $data = "")
    {
        $BASE_URL = 'https://pritunl.haohaozhu.me';
        $API_TOKEN = 'EIft2hD6lpIonF1WlkRSsIqfaBFQSGGt';
        $API_SECRET = 'IZmQxewSP6jCyDdAeMbjsCrPmiE7onkx';
        $client = new Client([
            'base_uri' => $BASE_URL,
            'headers'  => [
                'Content-Type' => 'application/json',
                'Auth-Token'   => $API_TOKEN
            ]
        ]);
        $auth_timestamp = strval(time());
        $auth_nonce = md5(uniqid());
        $auth_array = array(
            $API_TOKEN,
            $auth_timestamp,
            $auth_nonce,
            strtoupper($method),
            $path,
        );
        $auth_string = implode("&", $auth_array);
        $auth_signature = base64_encode(hash_hmac("sha256", $auth_string, $API_SECRET, true));
        try {
            $response = $client->request(strtoupper($method), $path, [
                'headers' => [
                    'Auth-Timestamp' => $auth_timestamp,
                    'Auth-Nonce'     => $auth_nonce,
                    'Auth-Signature' => $auth_signature
                ],
                'json'    => $data
            ]);
            return json_decode($response->getBody()->getContents(), true);
        } catch (\Exception $e) {
            return false;
        }
    }
}
